import { SceneType } from "../../../../../Core/Module/Entity/SceneType";
import { InstanceIdStruct } from "../../../../../Core/Module/IdGenerater/IdGenerater";
import { ExpandOf } from "../../../../../Decorator/Decorator";
import { List } from "../../../../../Support/Share/Lib/Collections/List";
import { Dictionary } from "../../../../../Support/Share/Lib/Dictionary";
import { MultiMap } from "../../../../../Support/Share/Lib/MultiMap";
import { StartProcessConfig, StartProcessConfigCategory } from "../Config/StartProcessConfig";
import { StartSceneConfig, StartSceneConfigCategory } from "../Config/StartSceneConfig";
import { StartZoneConfig, StartZoneConfigCategory } from "../Config/StartZoneConfig";

/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "../Config/StartSceneConfig" {

    interface StartSceneConfigCategory {

        Gates: MultiMap<number, StartSceneConfig>;

        ProcessScenes: MultiMap<number, StartSceneConfig>;

        ClientScenesByName: Dictionary<number, Dictionary<string, StartSceneConfig>>;

        LocationConfig: StartSceneConfig;

        Realms: Dictionary<number, StartSceneConfig>;

        Routers: List<StartSceneConfig>;

        Robots: List<StartSceneConfig>;

        BenchmarkServer: StartSceneConfig;

        GetByProcess(process: number): StartSceneConfig[];

        GetBySceneName(zone: number, name: string): StartSceneConfig;

        GetUnitCacheConfig(unitId: number): StartSceneConfig;

    }

}

@ExpandOf(StartSceneConfigCategory)
export class StartSceneConfigCategoryExpand {

    private static GetByProcess(self: StartSceneConfigCategory, process: number): StartSceneConfig[] {
        return self.ProcessScenes.TryGetValue(process);
    }

    private static GetBySceneName(self: StartSceneConfigCategory, zone: number, name: string): StartSceneConfig {
        return self.ClientScenesByName[zone][name];
    }

    private static AfterEndInit(self: StartSceneConfigCategory): void {
        for (const kv of self.GetAll()) {
            const startSceneConfig = kv[1];
            self.ProcessScenes.Add(startSceneConfig.Process, startSceneConfig);
            if (!self.ClientScenesByName[startSceneConfig.Zone]) {
                self.ClientScenesByName[startSceneConfig.Zone] = new Dictionary<string, StartSceneConfig>();
            }
            self.ClientScenesByName[startSceneConfig.Zone][startSceneConfig.Name] = startSceneConfig;
            switch (startSceneConfig.Type) {
                case SceneType.Realm:
                    self.Realms.Add(startSceneConfig.Zone, startSceneConfig);
                    break;
                case SceneType.Gate:
                    self.Gates.Add(startSceneConfig.Zone, startSceneConfig);
                    break;
                case SceneType.Location:
                    self.LocationConfig = startSceneConfig;
                    break;
                case SceneType.Robot:
                    self.Robots.Add(startSceneConfig);
                    break;
                case SceneType.Router:
                    self.Routers.Add(startSceneConfig);
                    break;
                case SceneType.BenchmarkServer:
                    self.BenchmarkServer = startSceneConfig;
                    break;
            }
        }
    }

}

StartSceneConfigCategory.prototype.Gates = new MultiMap<number, StartSceneConfig>();
StartSceneConfigCategory.prototype.ProcessScenes = new MultiMap<number, StartSceneConfig>();
StartSceneConfigCategory.prototype.ClientScenesByName = new Dictionary<number, Dictionary<string, StartSceneConfig>>();
StartSceneConfigCategory.prototype.Realms = new Dictionary<number, StartSceneConfig>();
StartSceneConfigCategory.prototype.Routers = new List<StartSceneConfig>();
StartSceneConfigCategory.prototype.Robots = new List<StartSceneConfig>();

/**
 * 使用 Expand 扩展方法
 * 
 * 必须作出以下申明，才能调用对象的扩展方法
 */
declare module "../Config/StartSceneConfig" {

    interface StartSceneConfig {

        InstanceId: number;

        Type: SceneType;

        readonly StartProcessConfig: StartProcessConfig;

        readonly StartZoneConfig: StartZoneConfig;

        readonly InnerIPOutPort: string;

        readonly OuterIPPort: string;

    }

}

@ExpandOf(StartSceneConfig)
export class StartSceneConfigExpand {

    private static AfterEndInit(self: StartSceneConfig) {
        self.Type = SceneType[self.SceneType];
        const instanceIdStruct = InstanceIdStruct.CreateWith(self.Process, self.Id);
        self.InstanceId = instanceIdStruct.ToLong();
    }

}

Object.defineProperty(StartSceneConfig.prototype, "StartProcessConfig", {
    get() {
        return StartProcessConfigCategory.Instance.Get(this.Process);
    }
});

Object.defineProperty(StartSceneConfig.prototype, "StartZoneConfig", {
    get() {
        return StartZoneConfigCategory.Instance.Get(this.Zone);
    }
});

Object.defineProperty(StartSceneConfig.prototype, "InnerIPOutPort", {
    get() {
        return `${this.StartProcessConfig.InnerIP}:${this.OuterPort}`;
    }
});

Object.defineProperty(StartSceneConfig.prototype, "OuterIPPort", {
    get() {
        return `${this.StartProcessConfig.OuterIP}:${this.OuterPort}`;
    }
});